﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using Framework.Business;
using Framework.Helper;
using MongoDB.Driver;
using RealDataReceiver.Entities;

namespace RealDataReceiver.DataAccess
{
    public interface IChannelDA
    {
        List<Channel> GetAllChannels();
        string GetLocationName(string locationId);
        string GetDeviceName(string locationId, string deviceId);
        Signal GetSignal(string locationId, string deviceId, string propertyId);

        IMongoCollection<Channel> GetCollection();
    }
    public class ChannelDA : IChannelDA
    {
        private readonly IMongoCollection<Channel> _mongoCollectionHistory;
        private ChannelDA()
        {
            var client = new MongoClient(ConfigurationHelper.GetConfiguration("ConnectionString"));
            var database = client.GetDatabase(ConfigurationHelper.GetConfiguration("DBInstance"));
            _mongoCollectionHistory = database.GetCollection<Channel>(ConfigurationHelper.GetConfiguration("ChannelCollection"));
        }

        static ChannelDA()
        {
            InstanceManager.RegisterBuilder<IChannelDA, ChannelDA>(() => new ChannelDA());
        }

        public static IChannelDA Instance
        {
            get { return InstanceManager.GetInstance<IChannelDA>(); }
        }

        public IMongoCollection<Channel> Collection
        {
            get { return _mongoCollectionHistory; }
        }

        public IMongoCollection<Channel> GetCollection()
        {
            return _mongoCollectionHistory;
        }

        private CacheItemPolicy GetCachePolicy()
        {
            var mins = ConfigurationHelper.GetInteger("CacheMinutes", 60);
            return new CacheItemPolicy
            {
                SlidingExpiration = new TimeSpan(0, mins, 0)
            };
        }

        public List<Channel> GetAllChannels()
        {
            try
            {
                return MemoryCacheHelper.Instance.GetOrAddObject($"AllChannels", GetCachePolicy(), () =>
                    {
                        return _mongoCollectionHistory.AsQueryable(new AggregateOptions {AllowDiskUse = true}).ToList();
                    });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
        public string GetLocationName(string locationId)
        {
            try
            {
                return MemoryCacheHelper.Instance.GetOrAddObject($"{locationId}", GetCachePolicy(), () => {
                    return _mongoCollectionHistory.AsQueryable(new AggregateOptions { AllowDiskUse = true })
                        .FirstOrDefault(r => r.ChannelId == locationId)
                        ?.ChannelName;
                });
                
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        public string GetDeviceName(string locationId,string deviceId)
        {
            try
            {
                return MemoryCacheHelper.Instance.GetOrAddObject($"{locationId}|{deviceId}", GetCachePolicy(), () =>
                {
                    return _mongoCollectionHistory.AsQueryable(new AggregateOptions {AllowDiskUse = true})
                        .FirstOrDefault(r => r.ChannelId == locationId)
                        ?.DeviceList.FirstOrDefault(d => d.DeviceId == deviceId)?.DeviceName;
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        public Signal GetSignal(string locationId, string deviceId, string propertyId)
        {
            try
            {
                return MemoryCacheHelper.Instance.GetOrAddObject($"{locationId}|{deviceId}|{propertyId}", GetCachePolicy(), () =>
                {
                    return _mongoCollectionHistory.AsQueryable(new AggregateOptions {AllowDiskUse = true})
                        .FirstOrDefault(r => r.ChannelId == locationId)
                        ?.DeviceList.FirstOrDefault(d => d.DeviceId == deviceId)
                        ?.SignalList.FirstOrDefault(s => s.SignalId == propertyId);
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
    }
}